package com.jiang.controller;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

@RestController
public class UploadController {

	private static final Logger logger = LoggerFactory.getLogger(UploadController.class);

	@Value("${upload.directory}")
	private String uploadDirectory;

	@Autowired
	private ThreadPoolTaskExecutor taskExecutor;

	/**
	 * 支持 单文件传 和 分片上传的接口 <br>
	 * 
	 * 单文件传：totalChunks == 1 保存单文件
	 * 
	 * @param file
	 * @param md5
	 * @param chunkNumber
	 * @param totalChunks
	 * @return
	 * @throws IOException
	 */
	@PostMapping("/upload")
	public String upload(@RequestParam("file") MultipartFile file, @RequestParam("md5") String md5,
			@RequestParam("chunkNumber") int chunkNumber, @RequestParam("totalChunks") int totalChunks)
			throws IOException {

		if (file.isEmpty()) {
			logger.warn("上传的文件为空");
			return "文件为空";
		}

		// 获取文件名
		String originalFilename = file.getOriginalFilename();
		logger.info("开始上传文件: {}, 分片: {}/{}", originalFilename, chunkNumber, totalChunks);

		// 使用配置的上传目录
		File uploadPath = new File(uploadDirectory);
		if (!uploadPath.exists()) {
			uploadPath.mkdirs();
		}

		// totalChunks = 1，单文件上传
		if (chunkNumber == totalChunks && totalChunks == 1) {
			// 构建目标文件路径
			Path targetLocation = Paths.get(uploadDirectory).resolve(originalFilename);

			// 保存文件
			try (FileOutputStream fos = new FileOutputStream(targetLocation.toFile())) {
				fos.write(file.getBytes());
			}

			logger.info("文件保存成功: {}", targetLocation);
			return "文件上传成功: " + originalFilename;
		}

		// 分片文件名
		String chunkFileName = originalFilename + ".part" + chunkNumber;
		File chunkFile = new File(uploadPath, chunkFileName);

		// 保存分片文件
		file.transferTo(chunkFile);
		logger.info("分片文件保存成功: {}", chunkFileName);

		// MD5校验
		String calculatedMd5 = calculateMd5(chunkFile);
		if (!calculatedMd5.equals(md5)) {
			chunkFile.delete();
			logger.error("MD5校验失败，分片: {}", chunkNumber);
			return "MD5校验失败，请重新上传分片";
		}
		logger.info("MD5校验成功，分片: {}", chunkNumber);

		// 检查是否所有分片都已上传
		if (chunkNumber == totalChunks) {
			logger.info("所有分片上传完成，开始合并文件: {}", originalFilename);
			CompletableFuture.runAsync(() -> {
				try {
					mergeChunks(originalFilename, totalChunks, uploadDirectory);
				} catch (IOException e) {
					logger.error("文件合并失败: {}", originalFilename, e);
				}
			}, taskExecutor);
			return "所有分片上传完成，正在合并文件";
		}

		return "分片 " + chunkNumber + " 上传成功";
	}

	// 计算文件的MD5值
	private String calculateMd5(File file) throws IOException {
		String md5 = DigestUtils.md5DigestAsHex(Files.newInputStream(file.toPath()));
		logger.debug("计算MD5值: {}", md5);
		return md5;
	}

	// 合并分片文件
	private void mergeChunks(String fileName, int totalChunks, String uploadDir) throws IOException {
		logger.info("开始合并文件: {}", fileName);
		File mergedFile = new File(uploadDir, fileName);
		try (FileOutputStream fos = new FileOutputStream(mergedFile)) {
			for (int i = 1; i <= totalChunks; i++) {
				File chunkFile = new File(uploadDir, fileName + ".part" + i);
				Files.copy(chunkFile.toPath(), fos);
				chunkFile.delete();
				logger.info("合并并删除分片: {}.part{}", fileName, i);
			}
		}
		logger.info("文件合并完成：{}", fileName);
	}

	/**
	 * 基础的上传文件的接口
	 * 
	 * @param file
	 * @return
	 * @throws IOException
	 */
	@PostMapping("/upload2")
	public String upload(@RequestParam("file") MultipartFile file) throws IOException {
		if (file.isEmpty()) {
			logger.warn("上传的文件为空");
			return "文件为空";
		}

		// 获取文件名
		String originalFilename = file.getOriginalFilename();
		logger.info("开始上传文件: {}", originalFilename);

		// 使用配置的上传目录
		File uploadPath = new File(uploadDirectory);
		if (!uploadPath.exists()) {
			uploadPath.mkdirs();
		}

		// 构建目标文件路径
		Path targetLocation = Paths.get(uploadDirectory).resolve(originalFilename);

		// 保存文件
		try (FileOutputStream fos = new FileOutputStream(targetLocation.toFile())) {
			fos.write(file.getBytes());
		}

		logger.info("文件保存成功: {}", targetLocation);
		return "文件上传成功: " + originalFilename;
	}

	/**
	 * 接收 JSON 格式的表单数据
	 *
	 * @param formData 包含 name 和 fileName 的 JSON 数据
	 * @return
	 */
	@PostMapping("/form1")
	public String form1(@RequestBody Map<String, Object> formData) {
		// 从 Map 中获取 name 和 fileName
		String name = (String) formData.get("name");
		String fileName = (String) formData.get("fileName");

		if (name == null || fileName == null) {
			logger.warn("缺少必要的参数: name 或 fileName");
			return "缺少必要的参数: name 或 fileName";
		}

		logger.info("接收到表单数据: name={}, fileName={}", name, fileName);
		// 你可以在这里进行进一步的处理，比如保存到数据库等
		return "表单提交成功: name=" + name + ", fileName=" + fileName;
	}

}
